#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <numeric>
#include <ranges>
#include <vector>
#include <rapidcsv.h>
#include <fmt/format.h>
using namespace std;

int main()
{
    rapidcsv::Document titantic{ "titanic.csv", rapidcsv::LabelParams(), rapidcsv::SeparatorParams{}, rapidcsv::ConverterParams(true) };
    auto survived{ titantic.GetColumn<int>("survived") };
    auto sex{ titantic.GetColumn<std::string>("sex") };
    auto age{ titantic.GetColumn<double>("age") };
    auto pclass{ titantic.GetColumn<int>("pclass") };

    std::cout << fmt::format("First five rows:\n{:<10}{:<8}{:<6}{}\n", "survived", "sex", "age", "pclass");
    for (size_t i{ 0 }; i < 5; ++i)
    {
        std::cout << fmt::format("{:<10}{:<8}{:<6.1f}{}\n", survived.at(i), sex.at(i), age.at(i), pclass.at(i));
    }
    std::cout << "....\n";
    const auto cnt{ titantic.GetRowCount() };
    for (std::size_t i{ cnt - 5 }; i < cnt; ++i)
    {
        std::cout << fmt::format("{:<10}{:<8}{:<6.1f}{}\n", survived.at(i), sex.at(i), age.at(i), pclass.at(i));
    }
    //auto remove
    auto removeNaN{ age | std::views::filter([](const auto &x) { return !isnan(x); }) };
    std::vector<double> cleanAge{ std::begin(removeNaN), std::end(removeNaN) };

    //descriptive statistics
    std::sort(std::begin(cleanAge), std::end(cleanAge));
    std::size_t size{ cleanAge.size() };
    double median{};
    if (size % 2 == 0)
    {
        median = (cleanAge.at(size / 2 - 1) + cleanAge.at(size / 2)) / 2;
    }
    else
    {
        median = cleanAge.at(size / 2);
    }
    std::cout << "\nDescriptive statistics for the age column:\n"
              << fmt::format("Passenger with age data:{}\n", size)
              << fmt::format("Average age: {:<.2f}\n", std::accumulate(std::begin(cleanAge), std::end(cleanAge), 0.0) / size)
              << fmt::format("Minimum age: {:<.2f}\n", cleanAge.front())  //
              << fmt::format("Maximum age: {:<.2f}\n", cleanAge.back())   //
              << fmt::format("Median age: {:<.2f}\n", median);

    // count all class
    auto countClass{ [](const auto &column, const int classNumber)
                     { return std::ranges::count_if(column, [classNumber](int x) { return classNumber == x; }); } };

    constexpr int firstClass{ 1 };
    constexpr int secondClass{ 2 };
    constexpr int thirdClass{ 3 };

    const auto firstCount{ countClass(pclass, firstClass) };
    const auto secondCount{ countClass(pclass, secondClass) };
    const auto thirdCount{ countClass(pclass, thirdClass) };

    std::cout << "\nPassenger counts by class:\n" << fmt::format("1st: {}\n2nd: {}\n3rd: {}\n\n", firstCount, secondCount, thirdCount);

    const auto survivorCount{ std::ranges::count_if(survived, [](auto x) { return x; }) };
    std::cout << fmt::format("Survived count:{}\nDied count:{}\n", survivorCount, survived.size() - survivorCount);
    std::cout << fmt::format("Persent who survived:{:.2f}%\n", 100.0 * survivorCount / survived.size());

    //
    int survivingMen{ 0 };
    int survivingWomen{ 0 };
    int surviving1st{ 0 };
    int surviving2nd{ 0 };
    int surviving3rd{ 0 };

    for (size_t i{ 0 }; i < survived.size(); ++i)
    {
        if (survived.at(i))
        {
            sex.at(i) == "female" ? ++survivingWomen : ++survivingMen;
            if (firstClass == pclass.at(i))
            {
                ++surviving1st;
            }
            else if (secondClass == pclass.at(i))
            {
                ++surviving2nd;
            }
            else if (thirdClass == pclass.at(i))
            {
                ++surviving3rd;
            }
        }
    }

    std::cout << fmt::format("Female survivor percentage: {:.2f}%\n", 100.0 * survivingWomen / survivorCount);
    std::cout << fmt::format("Male survivor percentage: {:.2f}%\n", 100.0 * survivingMen / survivorCount);
    std::cout << fmt::format("1st class percentage: {:.2f}%\n", 100.0 * surviving1st / survivorCount);
    std::cout << fmt::format("2nd class percentage: {:.2f}%\n", 100.0 * surviving2nd / survivorCount);
    std::cout << fmt::format("3rd class percentage: {:.2f}%\n", 100.0 * surviving3rd / survivorCount);

    return 0;
}
